package com.xiyuan.smartutils.loader;

import com.xiyuan.smartutils.*;

import java.io.File;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.BiConsumer;

/**
 * the description for class NativeLoader
 *
 * @author xiyuan-lgz 2025-06-22 @version v1.0.0 新建与整理
 */
final class NativeLoader {
    
    public static final int JAVA_MAIN_VERSION;
    public static final String OS_NAME;
    public static final String OS_ARCH;
    private static final String LIB_NAME = "gz-utils-native";
    
    static {
        String property = System.getProperty("java.specification.version");
        if (property.startsWith("1.")) {
            property = property.substring(2);
        }
        JAVA_MAIN_VERSION = Integer.parseInt(property);
        OS_NAME = System.getProperty("os.name");
        OS_ARCH = System.getProperty("os.arch");
    }
    
    
    // 0=初始化中未初始化、1=初始化中、2=初始化完成 ，3= 初始化失败
    private static volatile int initStep = 0;
    private static ReentrantLock LOCK = new ReentrantLock();
    
    
    private static void initNative() {
        if (initStep != 0) {
            return;
        }
        String path = Files.toLinuxPath(StrUtils.trimRight(Jars.getJarFilePath(Systems.class), "/"));
        if (StrUtils.isBlank(path)) {
            return;
        }
        try {
            LOCK.lock();
            initStep = 1;
            AtomicLong start = new AtomicLong(System.currentTimeMillis());
            
            
            String jar_lib_path = "/META-INF/jni/";
            String temp_lib_dir = TempFiles.getNativeDir();
            System.out.println("Load native library getNativeDir time: " + (System.currentTimeMillis() - start.get()) + ":" + (start.getAndSet(
                    System.currentTimeMillis())) + " ");
            BiConsumer<String, byte[]> func2 = (String name, byte[] bs) -> {
                if (StrUtils.isNotBlank(name) && bs != null) {
                    TempFiles.addTempLibFile(bs, name);
                }
            };
            if ((path.toLowerCase().endsWith("jar") || path.toLowerCase().endsWith("zip"))) {
                String prefix = StrUtils.trimLeft(jar_lib_path, "/");
                Jars.getFiles(path, (j) -> j.startsWith(prefix)).forEach(r -> {
                    if (!r.isDirectory()) {
                        String name = Files.toLinuxPath(r.getName());
                        name = name.substring(prefix.length());
                        func2.accept(name, Resources.getResourceBytes(Systems.class, r.getName()));
                    }
                });
            }
            else if (Files.isDirectory(path)) {
                String pathname = path + jar_lib_path;
                String prefix = StrUtils.addEndsWith(Files.toLinuxPath(new File(pathname).getCanonicalPath()), "/");
                Files.listFiles(new File(path), r -> Files.toLinuxPath(r).startsWith(prefix))
                        .forEach(r -> {
                            String name = Files.toLinuxPath(r);
                            name = name.substring(prefix.length());
                            func2.accept(name, Files.read(r));
                        });
            }
            
            List<String> lib_dirs = TempFiles.getNativeDirs();
            Systems.addLibraryPaths(lib_dirs);
            String arch = StrUtils.trimToNull(Systems.getOsArch().toLowerCase());
            switch (arch) {
                case "x86":
                    arch = "x86";
                    break;
                case "x86_64":
                case "amd64":
                    arch = "x86_64";
                    break;
                case "arm":
                    arch = "arm";
                    break;
                case "aarch64":
                    arch = "aarch64";
                    break;
                case "armhf":
                case "armv7":
                case "armv7l":
                case "armv7hf":
                    arch = "armhf_v7_v7l_v7hf";
                    break;
                
            }
            
            StringBuilder strb = new StringBuilder((Systems.isWindows() ? "" : "lib"));
            strb.append(LIB_NAME).append("_").append(getLabForOS());
            strb.append("_").append(arch);
            strb.append(Systems.getLibSuffix());
            path = temp_lib_dir + "/" + strb;
            if (Files.exists(path)) {
                start.set(System.currentTimeMillis());
                System.load(path);
                System.out.println("Load native library time: " + (System.currentTimeMillis() - start.get()) + ":" + (start.getAndSet(
                        System.currentTimeMillis())) + " ");
            }
            initStep = 2;
        }
        catch (RuntimeException e) {
            initStep = 3;
            throw e;
        }
        catch (Exception e) {
            initStep = 3;
            throw new RuntimeException(e);
        }
        finally {
            LOCK.unlock();
        }
    }
    
    private static String getLabForOS() {
        String[] osNs = Systems.getOsName().split(" ");
        if (osNs.length == 0) {
            return "";
        }
        String osName = osNs[0];
        if (StrUtils.startsWithIgnoreCase(osName, "windows")) {
            return "windows";
        }
        
        if (StrUtils.startsWithIgnoreCase(osName, "android")) {
            return "android";
        }
        
        if (StrUtils.startsWithIgnoreCase(osName, "ios")) {
            return "ios";
        }
        
        if (StrUtils.startsWithIgnoreCase(osName, "macos")) {
            return "macos";
        }
        
        if (StrUtils.startsWithIgnoreCase(osName, "linux")) {
            return "linux";
        }
        
        return osName;
    }
    
    public static void init() {
        initNative();
    }

//    static {
//        init();
//    }
}
